import { Link } from '@brillout/docpress'


## Unit tests

Using Vitest for unit tests should work out of the box.

> By default, <Link href="/vite-plugin">Vike's Vite plugin</Link> isn't loaded when running Vitest.
>
> This is because Vitest is typically used for unit tests, where Vike's Vite plugin doesn't add any value. For that reason, Vike's Vite plugin removes itself when it detects Vitest.
>
> If you do want Vike's Vite plugin to be loaded, use Vike's JavaScript API (Vike's Vite plugin won't remove itself then) — see <Link href="#with-vike-e2e" />.


## With Vike (e2e)

If you want to use Vitest to test your whole Vike app (typically for end-to-end tests), use <Link href="/api">Vike's JavaScript API</Link>:

```ts
// dev.spec.ts

import { afterAll, beforeAll } from 'vitest'
import { testApp, viteConfig } from './testApp'
import { dev } from 'vike/api'

let viteServer: Awaited<ReturnType<typeof dev>>['viteServer']

beforeAll(async () => {
  const { viteServer } = await dev({ viteConfig })
  await viteServer.listen()
  await sleep(10) // avoid race condition of server not actually being ready
}, 10 * 1000)

afterAll(async () => {
  await viteServer.close()
})

testApp()

function sleep(milliseconds: number): Promise<void> {
  return new Promise((r) => setTimeout(r, milliseconds))
}
```

> Make sure to use Vike's JavaScript API — not [Vite's API](https://vite.dev/guide/api-javascript). (When using Vike's JavaScript API, <Link href="#unit-tests">Vike's Vite pugin won't remove itself</Link>.)

```ts
// preview.spec.ts

import { afterAll, beforeAll } from 'vitest'
import { testApp, viteConfig } from './testApp'
import { build, preview } from 'vike/api'

let viteServer: Awaited<ReturnType<typeof preview>>['viteServer']

beforeAll(async () => {
  await build({ viteConfig })
  const { viteServer } = await preview({ viteConfig })
  // If you want to replicate Vite's startup log:
  viteServer!.printUrls()
  // For the preview server, no need to call server.listen()
}, 40 * 1000)

afterAll(async () => {
  await viteServer!.close()
})

testApp()
```

```ts
// testApp.ts

export { testApp }
export { viteConfig }

import { expect, describe, it } from 'vitest'

const viteConfig = {
  logLevel: 'warn' as const,
  root: __dirname,
  configFile: __dirname + '/vite.config.js'
}
const urlBase = 'http://localhost:3000'

function testApp() {
  describe('Vitest', () => {
    it('run Vitest with Vike', { timeout: 10 * 1000 }, async () => {
      {
        const html = await fetchHtml('/')
        expect(html).toContain('<h1>Welcome</h1>')
        expect(html).toContain('<li>Rendered to HTML.</li>')
      }
      {
        const html = await fetchHtml('/about')
        expect(html).toContain('<h1>About</h1>')
        expect(html).toContain('<p>Example of using Vike.</p>')
      }
    })
  })
}

async function fetchHtml(urlPathname: string) {
  const ret = await fetch(urlBase + urlPathname)
  const html = await ret.text()
  return html
}
```
